let fac = x => {
    if (x === 0) {
        return 1
    } else {
        return x * fac(x - 1)
    }
}

let fac2 = (self, x) => {
    if (x === 0) {
        return 1
    } else {
        return x * self(self, x - 1)
    }
}

let fac3 =
    self => {
        return x => {
            if (x === 0) {
                return 1
            } else {
                return x * self(self)(x - 1)
            }
        }
    };

let fac4 =
    self => {
        return x => {
            let f =
                q => {
                    return x => {
                        if (x === 0) {
                            return 1
                        } else {
                            return x * q(x - 1)
                        }
                    }
                }
            return f(self(self))(x)
        }
    };

/*
Now we have our original f that we want the fixed point of.
The fixed point is the factorial function given by factorial(factorial),
so we can write our Y() function to return it:
f(Y(f))(x) = f(x)
f(Y(f)) = Y(f)
*/
let f =
    q => {
        return x => {
            if (x === 0) {
                return 1
            } else {
                return x * q(x - 1)
            }
        }
    };

let f2 =
    self => {
        return x => {
            if (x === 1) {
                return 1
            } else {
                return self(x - 1) + x
            }
        }
    };

let fac5 =
    self => {
        return x => {
            return f(self(self))(x)
        }
    };

// console.dir(
//     fac5(fac5)(4)
// )

// try doing somethings on fac5
let Y =
    f => {
        let q =
            self => {
                return x => {
                    return f(self(self))(x)
                }
            }
        return q(q)
    };

// target
let fac6 = Y(f2);
console.dir(
    fac6(4)
);

// f2(Y(f2))(x) = Y(f2)(x)

// let Y =
//     f => {
//
//         let fac5 =
//             self => {
//                 return x => {
//                     return f(self(self))(x)
//                 }
//             };
//         return fac5(fac5);
//
//     };

/*
var Y = function(f) {
  var g = function(h) {
    return function(x) {
      return f(h(h))(x);
    };
  };
  return g(g);
};

var Y = function(f) {
  return (function(g) {
    return g(g);
  })(function(h) {
    return function() {
      return f(h(h)).apply(null, arguments);
    };
  });
};
*/

